/*
	QUBE
	Sandra Obermann - QPT 1 - 2012
	fhs33730 - 1110601021
	FH Salzburg - Studiengang MultiMediaTechnolgy
*/

// Cinder Includes
#include "cinder/Utilities.h"

// Own written Includes
#include "../include/Level.h"

// Initialize Level with: width, height and depth with value 0
Level::Level()
{
	m_levelWidth = 0;
	m_levelHeight = 0;
	m_levelDepth = 0;
	m_finishPosition = ci::Vec3f::zero();
}

// Destructor for Level element which calls the killLevel function
Level::~Level()
{
	killLevel();
}

// Create Level and draw all BLOCKS
void Level::buildLevel()
{
	// build basic level bounds
	buildLevel( 30, 30, E_LEVEL_5 );

	// Finish
	m_finishPosition = ci::Vec3f(80, E_LEVEL_1, 70);

	// Add level content
	for (int i = 2; i < 23; i++) // bottom blocks big platform
	{	
		for(int j = 3; j < 9; j++)
		{
			AddLevelBlock(i, j, E_LEVEL_1);
		}
	}

	for(int i = 1; i < 2; i++) // bottom blocks front
	{
		for(int j = 3; j < 8; j++)
		{
			AddLevelBlock(i, j, E_LEVEL_1);
		}
	}

	for(int i = 2; i < 8; i++) // bottom blocks right short
	{
		for(int j = 10; j < 11; j++)
		{
			AddLevelBlock(i, j, E_LEVEL_1);
		}
	}

	for(int i = 2; i < 19; i++) // bottom blocks right long
	{
		for(int j = 9; j < 10; j++)
		{
			AddLevelBlock(i, j, E_LEVEL_1);
		}
	}

	for(int i = 23; i < 27; i++) // bottom blocks smaller platform right corner
	{
		for(int j = 10; j < 17; j++)
		{
			AddLevelBlock(i, j, E_LEVEL_1);
		}
	}

	for(int i = 18; i < 23; i++) // bottom blocks finish platform path
	{
		for(int j = 13; j < 16; j++)
		{
			AddLevelBlock(i, j, E_LEVEL_1);
		}
	}

	for(int i = 15; i < 18; i++) // colored bottom finish platform outside left and right blocks
	{
		for(int j = 13; j < 16; j+=2)
		{
			AddLevelBlock(i, j, E_LEVEL_1, ci::ColorA(0, 1, 1, 1));
		}
	}

	// Colored Blocks outside in the middle of platform with uncolored block in the middle
	AddLevelBlock(15, 14, E_LEVEL_1, ci::ColorA(0, 1, 1, 1));
	AddLevelBlock(16, 14, E_LEVEL_1);
	AddLevelBlock(17, 14, E_LEVEL_1, ci::ColorA(0, 1, 1, 1));

	for (int i = 22; i < 27; i++) // step platform first 2 rows beginning left
	{
		for(int j = 7; j < 9; j++)
		{
			AddLevelBlock(i, j, E_LEVEL_2);
		}
	}

	for (int i = 23; i < 27; i++) // step platform next 2 rows
	{
		for(int j = 9; j < 11; j++)
		{
			AddLevelBlock(i, j, E_LEVEL_2);
		}
	}

	for (int i = 24; i < 27; i++) //step platform last row
	{
		for(int j = 11; j < 12; j++)
		{
			AddLevelBlock(i, j, E_LEVEL_2);
		}
	}

	for(int i = 18; i < 21; i++) // Finish Line Blocks
	{
		for(int j = 13; j < 14; j++)
		{
			AddLevelBlock(i, j, E_LEVEL_2);
			AddLevelBlock(i, j+2, E_LEVEL_2);
		}
	}

	for (int i = 1; i < 9; i++) // Wall 1
	{
		for(int j = 1; j < 3; j++)
		{
			AddLevelBlock(i, j, E_LEVEL_2);
			AddLevelBlock(i, j, E_LEVEL_3);
			AddLevelBlock(i, j, E_LEVEL_4);
			AddLevelBlock(i, j, E_LEVEL_5);
		}
	}

	for(int i = 1; i < 2; i++) // Single Wall Left Corner
	{
		for(int j = 3; j < 4; j++)
		{
			AddLevelBlock(i, j, E_LEVEL_2);
			AddLevelBlock(i, j, E_LEVEL_3);
			AddLevelBlock(i, j, E_LEVEL_4);
			AddLevelBlock(i, j, E_LEVEL_5);
		}
	}

	for (int i = 8; i < 16; i++) // Wall 2
	{
		for(int j = 3; j < 7; j++)
		{
			AddLevelBlock(i, j, E_LEVEL_2);
			AddLevelBlock(i, j, E_LEVEL_3);
			AddLevelBlock(i, j, E_LEVEL_4);
			AddLevelBlock(i, j, E_LEVEL_5);
		}
	}

	for (int i = 16; i < 21; i++) // Wall 3
	{
		for(int j = 2; j < 6; j++)
		{
			AddLevelBlock(i, j, E_LEVEL_2);
			AddLevelBlock(i, j, E_LEVEL_3);
			AddLevelBlock(i, j, E_LEVEL_4);
			AddLevelBlock(i, j, E_LEVEL_5);
		}
	}

	for (int i = 21; i < 27; i++) // Wall 4
	{
		for(int j = 3; j < 7; j++)
		{
			AddLevelBlock(i, j, E_LEVEL_2);
			AddLevelBlock(i, j, E_LEVEL_3);
			AddLevelBlock(i, j, E_LEVEL_4);
			AddLevelBlock(i, j, E_LEVEL_5);
		}
	}

	for(int i = 27; i < 28; i++) // Wall 5
	{
		for(int j = 6; j < 17; j++)
		{
			AddLevelBlock(i, j, E_LEVEL_1);
			AddLevelBlock(i, j, E_LEVEL_2);
			AddLevelBlock(i, j, E_LEVEL_3);
			AddLevelBlock(i, j, E_LEVEL_4);
			AddLevelBlock(i, j, E_LEVEL_5);
		}
	}
}

// Create 3D Vector Array
void Level::buildLevel(int width,int height, int depth)
{
	m_levelWidth = width;
	m_levelHeight = height;
	m_levelDepth = depth;

	// initialize whole grid
	std::vector< std::vector<BLOCK*> > row;
	std::vector<BLOCK*> level;

	for (int i = 0; i < m_levelWidth; i++)
	{
		row.clear();

		for(int j = 0; j < m_levelHeight; j++)
		{
			level.clear();

			for(int k = 0; k <= m_levelDepth; k += GRID_SIZE)
			{
				// create "empty" grid in 3D space
				BLOCK* block = 0;
				level.push_back(block);
			}
			row.push_back(level);
		}
		m_blocks.push_back(row);
	}
}

// Add BLOCKS into the 3D Vector Array with position and color
void Level::AddLevelBlock( int x, int y, int z, ci::ColorA newBlockColor)
{
	// check if x,y,z is in range
	std::vector<BLOCK*>::iterator it;
	it = m_blocks.at(x).at(y).begin();
	BLOCK* block = m_blocks.at(x).at(y).at(z/GRID_SIZE);
	
	// if there is already a BLOCK, delete it
	if( block )
	{
		delete block;
	}

	// create new BLOCK
	block = new BLOCK(GRID_SIZE);
	block->setBlockPosition( ci::Vec3f( (float)x*GRID_SIZE, (float)z, (float)y*GRID_SIZE ) );
	block->setBlockColor(  newBlockColor );
	m_blocks.at(x).at(y).insert( it + z/GRID_SIZE, 1, block );
}

// Returns if there is a BLOCK in the 3D Vector Array on position xyz or not
BLOCK* Level::getLevelBlock( int x, int y, int z )
{
	// if the given position is outside the level bounds return (BLOCK*)-1;
	if( x < 0 || y < 0 || z < 0 || x > m_levelWidth || y > m_levelHeight || z > m_levelDepth || !m_blocks.size())
	{
		return (BLOCK*)-1;
	}

	// otherwise return the BLOCK
	return m_blocks.at(x).at(y).at(z);
}

// Kill Level with inserted BLOCKS from the 3D Vector Array
void Level::killLevel()
{
	if( m_blocks.size() )
	{
		for (unsigned int i = 0; i < m_blocks.size(); i++)
		{
			for(unsigned int j = 0; j < m_blocks.at(i).size(); j++)
			{
				for(unsigned int k = 0; k < m_blocks.at(i).at(j).size(); k++)
				{
					BLOCK *block = m_blocks.at(i).at(j).at(k);
					if( block )
					{
						delete block;
					}
				}
			}
		}
	}
}

// Draw Level with inserted BLOCKS into the 3D Vector Array
void Level::drawLevel()
{
	if( m_blocks.size() )
	{
		for (unsigned int i = 0; i < m_blocks.size(); i++)
		{
			for(unsigned int j = 0; j < m_blocks.at(i).size(); j++)
			{
				for(unsigned int k = 0; k < m_blocks.at(i).at(j).size(); k++)
				{
					BLOCK *block = m_blocks.at(i).at(j).at(k);
					if( block )
					{
						block->draw();
					}
				}
			}
		}
	}
}

ci::Vec3f Level::getFinishPosition()
{
	return m_finishPosition;
}